#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <ctime>

#include <nlohmann/json.hpp>

#include "DemoJson.h"

using namespace std;
using json = nlohmann::json;

void demoJson(void) {
    cout<<endl<<endl<<"demoJson"<<endl;
    
    // create an empty structure (null)
    json j;

    // add a number that is stored as double (note the implicit conversion of j to an object)
    j["pi"] = 3.141;

    // add a Boolean that is stored as bool
    j["happy"] = true;

    // add a string that is stored as std::string
    j["name"] = "Niels";

    // add another null object by passing nullptr
    j["nothing"] = nullptr;

    // add an object inside the object
    j["answer"]["everything"] = 42;

    // add an array that is stored as std::vector (using an initializer list)
    j["list"] = { 1, 0, 2 };

    // add another object (using an initializer list of pairs)
    j["object"] = { {"currency", "USD"}, {"value", 42.99} };
    
    cout<<"demoJson, j  = "<<j<<endl;
    
    
    
    // instead, you could also write (which looks very similar to the JSON above)
    json j2 = {
      {"pi", 3.141},
      {"happy", true},
      {"name", "Niels"},
      {"nothing", nullptr},
      {"answer", {
        {"everything", 42}
      }},
      {"list", {1, 0, 2}},
      {"object", {
        {"currency", "USD"},
        {"value", 42.99}
      }}
    };
    
    cout<<"demoJson, j2 = "<<j2<<endl;
    
    
    
    // 多行字符串 Raw string literals (C++11)
    string jsonStr = R"EOF(
    {
      "pi": 3.141,
      "happy": true,
      "name": "Niels",
      "nothing": null,
      "answer": {
        "everything": 42
      },
      "list": [1, 0, 2],
      "object": {
        "currency": "USD",
        "value": 42.99
      }
    }
    )EOF";
    
    json j3 = json::parse(jsonStr);
    cout<<"demoJson, j3 = "<<j3<<endl;
    
    cout<<"demoJson, j3.is_null()    "   <<j3.is_null()<<endl;
    cout<<"demoJson, j3.is_boolean() "   <<j3.is_boolean()<<endl;
    cout<<"demoJson, j3.is_number()  "   <<j3.is_number()<<endl;
    cout<<"demoJson, j3.is_object()  "   <<j3.is_object()<<endl;
    cout<<"demoJson, j3.is_array()   "   <<j3.is_array()<<endl;
    cout<<"demoJson, j3.is_string()  "   <<j3.is_string()<<endl;
    cout<<"demoJson, j3.size()       "   <<j3.size()<<endl;
    cout<<"demoJson, j3.empty()      "   <<j3.empty()<<endl;
    cout<<"demoJson, j3.type()       "   <<(int)(j3.type())<<endl;
    
    // 对于 json object
    for (auto& el : j3.items()) {
        cout<<"demoJson, j3 for loop, " << el.key() << " : " << el.value() <<endl;
    }
    
    // 删减一个键值对
    j3.erase("object");
    
    for (auto& el : j3.items()) {
        cout<<"demoJson, j3 after erase, for loop, " << el.key() << " : " << el.value() <<endl;
    }
    
    json jArr = json::array();
    jArr.push_back(3);
    jArr.push_back(4);
    jArr.push_back(5);
    // 对于 json array
    for (auto& el : jArr) {
        cout<<"demoJson, jArr, for loop, " << el <<endl;
    }
    
    // 序列化为字符串
    string j3StrFlat = j3.dump(); // 单行输出
    cout<<"demoJson, j3StrFlat = "<<j3StrFlat<<endl;
    
    string j3Str = j3.dump(2); // 分行，带缩进 2空格
    cout<<"demoJson, j3Str = "<<j3Str<<endl;
    
    //可扁平化所有键（全部展开成一层key-value，key为对应的路径
    cout<<"demoJson, j3.flatten() = "<<setw(4)<<j3.flatten()<<endl;
    

    
    // 解析异常，try catch
    string jsonStrErr = R"EOF(
    {
      "pi": 3.141,
      "happy": true,
      "name": "Niels",
      "nothing": null,
      "answer": {
        "everything": 42
      },
      "list": [1, 0, 2],
      "object": {
        "currency": "USD",
        "value": 42.99
      }，
      "list": [1, "zero", 2],
    }
    )EOF";
    
    try {
        // try to use an array index with leading '0'
        json j4 = json::parse(jsonStrErr);
        cout<<"demoJson, j4 = "<<j4<<endl;
    }
    catch (json::parse_error &e) {
        cout<<"demoJson, parse exception"<< e.what() << endl;
    }

}
